package enumx

import (
	"errors"
	"fmt"
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/tagx"
	"sync"
)

const (
	EnumValidTag = tagx.EnumTagName
)

var (
	enumHub = map[string]interface{}{}
	lock    sync.Mutex
)

// RegisterEnum 注册枚举
func RegisterEnum[T comparable](name string, e IEnum[T]) error {
	lock.Lock()
	defer lock.Unlock()
	_, ok := enumHub[name]
	if ok {
		return errors.New(fmt.Sprintf("enum [%s] exists", name))
	}

	enumHub[name] = e
	return nil
}

// GetEnum 获取枚举
func GetEnum[T comparable](name string) (IEnum[T], bool) {
	ei, ok := enumHub[name]
	if ok {
		return ei.(IEnum[T]), true
	}
	return nil, false
}

func GetEnum2(name string) (interface{}, bool) {
	ei, ok := enumHub[name]
	if ok {
		return ei, true
	}
	return nil, false
}

// IEnum 枚举接口
type IEnum[T comparable] interface {
	// Valid 校验枚举值是否合法
	Valid(value T) error
	// GetDesc 根据枚举值获取描述
	GetDesc(value T) string
	// GetValues 所有枚举值。枚举值 -> desc(描述)
	GetValues() map[T]string
}

// Enum 枚举默认实现
type Enum[T comparable] struct {
	name   string       // 枚举值名称
	values map[T]string // 所有枚举值。枚举值 -> desc(描述)
}

// NewEnum 新建枚举
func NewEnum[T comparable](name string) *Enum[T] {
	return &Enum[T]{
		name:   name,
		values: make(map[T]string),
	}
}

// Add 添加枚举值
func (e *Enum[T]) Add(value T, desc string) *Enum[T] {
	e.values[value] = desc
	return e
}

// Valid 校验枚举值是否合法
func (e *Enum[T]) Valid(value T) error {
	_, ok := e.values[value]
	if ok {
		return nil
	}

	errMsg := fmt.Sprintf("%s可选值为: ", e.name)
	for val, desc := range e.values {
		errMsg = fmt.Sprintf("%s [%v->%s]", errMsg, val, desc)
	}
	return errors.New(errMsg)
}

// GetDesc 根据枚举值获取描述
func (e *Enum[T]) GetDesc(value T) string {
	desc, ok := e.values[value]
	if ok {
		return desc
	}

	return ""
}

// GetValues 所有枚举值。枚举值 -> desc(描述)
func (e *Enum[T]) GetValues() map[T]string {
	return e.values
}
